#include "StdAfx.h"
#include "SkyBox.h"
#include <d3d9.h>
#include "GraphicsController.h"
#include "ICameraImpl.h"


///////////////////////////////////////////////////////////////////////////////

DWORD CSkyBoxVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;

///////////////////////////////////////////////////////////////////////////////

CSkyBox::CSkyBox(CGraphicsController& graphicsController,
           const std::wstring& topFaceTexFileName,
           const std::wstring& bottomFaceTexFileName,
           const std::wstring& frontFaceTexFileName,
           const std::wstring& backFaceTexFileName,
           const std::wstring& leftFaceTexFileName,
           const std::wstring& rightFaceTexFileName)
      : m_graphicsController(graphicsController)
{
   // define vertices
   m_vertices = graphicsController.createVertexBuffer(sizeof(CSkyBoxVertex) * 24, 
                                                      D3DUSAGE_WRITEONLY,
                                                      CSkyBoxVertex::FVF,
                                                      D3DPOOL_MANAGED);

   CSkyBoxVertex* pVertex = NULL;
   if (FAILED(m_vertices->Lock(0, 0, (void**)&pVertex, D3DLOCK_DISCARD)))
   {
      throw std::logic_error(
         std::string("Cannot lock a vertex buffer"));
   }

   // Front quad (remember all quads point inward)
   *pVertex++  = CSkyBoxVertex( -10.0f,  10.0f,  10.0f, 0.0f, 0.0f );
   *pVertex++  = CSkyBoxVertex(  10.0f,  10.0f,  10.0f, 1.0f, 0.0f );
   *pVertex++  = CSkyBoxVertex( -10.0f, -10.0f,  10.0f, 0.0f, 1.0f );
   *pVertex++  = CSkyBoxVertex(  10.0f, -10.0f,  10.0f, 1.0f, 1.0f );

   // Back Quad
   *pVertex++  = CSkyBoxVertex(  10.0f,  10.0f, -10.0f, 0.0f, 0.0f );
   *pVertex++  = CSkyBoxVertex( -10.0f,  10.0f, -10.0f, 1.0f, 0.0f );
   *pVertex++  = CSkyBoxVertex(  10.0f, -10.0f, -10.0f, 0.0f, 1.0f );
   *pVertex++  = CSkyBoxVertex( -10.0f, -10.0f, -10.0f, 1.0f, 1.0f );

   // Left Quad
   *pVertex++  = CSkyBoxVertex( -10.0f,  10.0f, -10.0f, 0.0f, 0.0f );
   *pVertex++  = CSkyBoxVertex( -10.0f,  10.0f,  10.0f, 1.0f, 0.0f );
   *pVertex++ = CSkyBoxVertex( -10.0f, -10.0f, -10.0f, 0.0f, 1.0f );
   *pVertex++ = CSkyBoxVertex( -10.0f, -10.0f,  10.0f, 1.0f, 1.0f );

   // Right Quad
   *pVertex++ = CSkyBoxVertex(  10.0f,  10.0f,  10.0f, 0.0f, 0.0f );
   *pVertex++ = CSkyBoxVertex(  10.0f,  10.0f, -10.0f, 1.0f, 0.0f );
   *pVertex++ = CSkyBoxVertex(  10.0f, -10.0f,  10.0f, 0.0f, 1.0f );
   *pVertex++ = CSkyBoxVertex(  10.0f, -10.0f, -10.0f, 1.0f, 1.0f );

   // Top Quad
   *pVertex++ = CSkyBoxVertex( -10.0f,  10.0f, -10.0f, 0.0f, 0.0f );
   *pVertex++ = CSkyBoxVertex(  10.0f,  10.0f, -10.0f, 1.0f, 0.0f );
   *pVertex++ = CSkyBoxVertex( -10.0f,  10.0f,  10.0f, 0.0f, 1.0f );
   *pVertex++ = CSkyBoxVertex(  10.0f,  10.0f,  10.0f, 1.0f, 1.0f );

   // Bottom Quad
   *pVertex++ = CSkyBoxVertex( -10.0f, -10.0f,  10.0f, 0.0f, 0.0f );
   *pVertex++ = CSkyBoxVertex(  10.0f, -10.0f,  10.0f, 1.0f, 0.0f );
   *pVertex++ = CSkyBoxVertex( -10.0f, -10.0f, -10.0f, 0.0f, 1.0f );
   *pVertex++ = CSkyBoxVertex(  10.0f, -10.0f, -10.0f, 1.0f, 1.0f );

   m_vertices->Unlock();

   // load texture
   D3DXCreateTextureFromFile(&(graphicsController.getD3Device()), frontFaceTexFileName.c_str(),  &(m_textures[0]));
   D3DXCreateTextureFromFile(&(graphicsController.getD3Device()), backFaceTexFileName.c_str(),   &(m_textures[1]));
   D3DXCreateTextureFromFile(&(graphicsController.getD3Device()), leftFaceTexFileName.c_str(),   &(m_textures[2]));
   D3DXCreateTextureFromFile(&(graphicsController.getD3Device()), rightFaceTexFileName.c_str(),  &(m_textures[3]));
   D3DXCreateTextureFromFile(&(graphicsController.getD3Device()), topFaceTexFileName.c_str(),    &(m_textures[4]));
   D3DXCreateTextureFromFile(&(graphicsController.getD3Device()), bottomFaceTexFileName.c_str(), &(m_textures[5]));
}

///////////////////////////////////////////////////////////////////////////////
CSkyBox::~CSkyBox(void)
{
   m_vertices->Release();
   m_vertices = NULL;

   for (int i = 0; i < 6; i++)
   {
      m_textures[i]->Release();
      m_textures[i] = NULL;
   }
}

///////////////////////////////////////////////////////////////////////////////

void CSkyBox::render(const ICameraImpl& camera)
{
   IDirect3DDevice9& d3Device = m_graphicsController.getD3Device();
   d3Device.SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
   d3Device.SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
   d3Device.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
   d3Device.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
   d3Device.SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);

   d3Device.SetFVF(CSkyBoxVertex::FVF);

   const D3DXVECTOR3& cameraPos = camera.getPosition();
   D3DXMATRIX mtxWorld;
   D3DXMatrixIdentity(&mtxWorld);
   mtxWorld._41 = cameraPos.x; mtxWorld._42 = cameraPos.y + 1.3f; mtxWorld._43 = cameraPos.z;
   d3Device.SetTransform(D3DTS_WORLD, &mtxWorld);

   d3Device.SetStreamSource(0, m_vertices, 0, sizeof(CSkyBoxVertex));

   for (int i = 0; i < 6; i++)
   {
      d3Device.SetTexture(0, m_textures[i]);
      d3Device.DrawPrimitive(D3DPT_TRIANGLESTRIP, i * 4, 2);
   }

   d3Device.SetTexture(0, NULL);

   d3Device.SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
   d3Device.SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
}

///////////////////////////////////////////////////////////////////////////////
